/**
  ******************************************************************************
  * @file    Project/m1130-EVAL/main.c 
  * @author  Alpscale Software Team 
  * @version V1.0.0
  * @date    19-December-2013
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, ALPHASCALE SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2013 Alphascale</center></h2>
  ******************************************************************************
  */  

/* Includes ------------------------------------------------------------------*/
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "m1130_uart.h" 
#include "m1130_gpio.h" 
#include "m1130_rcc.h"	 
#include "misc.h"
#include "m1130_dma.h"
#include "m1130_wdg.h"
#include "m1130_qspi.h"	 
#include "m1130_eval_qspi.h"
#include "m1130_utility_usart.h"


void qspiSlaverDma_IRQHandler(void);
int qspi_dma_read(QSPI_TypeDef *QSPI, void *buff, int size, FunctionalState isEnIrq)
{
  uint32_t temreg;
  DMAChannel_TypeDef *RxChannel;
  DMAchannel channel;

  channel = DmaRequestChannel(qspiSlaverDma_IRQHandler);
  if ((int)channel >= DMAChannelNum) {
    printf("all dma channel busy\r\n");
    return -1;
  }
  DmaChannelInterrupt(channel, isEnIrq);//dma??????
  DmaChannelClearInterruptStatus(channel);

  RxChannel = (DMAChannel_TypeDef *)(DMA_BASE + 0x58*channel);

  DMA->DmaCfgReg = 1;
  /*rx dma init*/
  temreg = 0x00000000 + (1 << DMA_CTRL_INT_EN)  //INT_EN, ch0 irq disable
                      + (2 << DMA_CTRL_DST_TR_WIDTH)      // DST_TR_WIDTH, des transfer width, should set to HSIZE, here is 000, means 8bit
                      + (2 << DMA_CTRL_SRC_TR_WIDTH)      // SRC_TR_WIDTH, sor transfer width, should set to HSIZE, here is 000, means 8bit
                      + (0 << DMA_CTRL_DINC)      // DINC, des addr increment, des is SPI, so should set to 1x, means no change
                      + (2 << DMA_CTRL_SINC)      // SINC, sor addr increment, src is sram, so should set to 00, means to increase 
                      + (0 << DMA_DEST_MSIZE)     // DEST_MSIZE, des burst length, set to 001 means 4 DST_TR_WIDTH per burst transcation
                      + (0 << DMA_SRC_MSIZE)     // SRC_MSIZE, sor burst length, set to 001 means 4 SOR_TR_WIDTH per burst transcation
                      + (2 << DMA_TTC_FC)     // TT_FC,transfer type and flow control,001 means memory to peripheral,dma is flow controller
                      + (0 << DMA_DMS)     // DMS, des master select, 0 means ahb master 0
                      + (0 << DMA_SMS)     // SMS, sor master select, 0 means ahb master 0
                      + (0 << DMA_LLP_DST_EN)     // LLP_DST_EN, des block chaining enable, set to 0 disable it
                      + (0 << DMA_LLP_SRC_EN) ;   // LLP_SOR_EN, sor block chaining enable, set to 0 disable it	
  if (QSPI == QSPI0)
  {
    RxChannel->CFG_H = (REQ_QSPI0RX << DMA_CFG_SRC_PER) + (REQ_QSPI0RX << DMA_CFG_DEST_PER);
  }
  else if (QSPI == QSPI1)
  {
    RxChannel->CFG_H = (REQ_QSPI1RX << DMA_CFG_SRC_PER) + (REQ_QSPI1RX << DMA_CFG_DEST_PER);
  }
  else if (QSPI == QSPI2)
  {
    RxChannel->CFG_H = (REQ_QSPI2RX_TIM15 << DMA_CFG_SRC_PER) + (REQ_QSPI2RX_TIM15 << DMA_CFG_DEST_PER);
  }
  RxChannel->CFG_L = 0;
  RxChannel->CTL_L = temreg;
  RxChannel->SAR = (uint32_t)&QSPI->DATA;
  RxChannel->DAR = (uint32_t)buff;
  RxChannel->CTL_H = size/4;
  RxChannel->LLP = 0;

  QSPI->XFER = size;
  QSPI->CTRL1_SET = 1 << 13;
  QSPI->CTRL0_SET = 0x34000000;
  DMA->ChEnReg = 0x101 << channel;
  
  while (DMA->ChEnReg & (0x01 << channel))
    ;

  if (isEnIrq) return channel;
  DmaFreeChannel(channel);
  return 0;
}

int qspi_dma_write(QSPI_TypeDef *QSPI, void *buff, int size, FunctionalState isEnIrq)
{
  uint32_t temreg;
  DMAChannel_TypeDef *TxChannel;
  DMAchannel channel;

  channel = DmaRequestChannel(qspiSlaverDma_IRQHandler);
  if ((int)channel >= DMAChannelNum) {
    printf("all dma channel busy\r\n");
    return -1;
  }
  DmaChannelInterrupt(channel, isEnIrq);//dma??????
  TxChannel = (DMAChannel_TypeDef *)(DMA_BASE + 0x58*channel);

  DMA->DmaCfgReg = 1;
  /*tx dma init*/
  temreg = 0x00000000 + (1 << DMA_CTRL_INT_EN)  //INT_EN, ch0 irq disable
                      + (0 << DMA_CTRL_DST_TR_WIDTH)      // DST_TR_WIDTH, des transfer width, should set to HSIZE, here is 000, means 8bit
                      + (0 << DMA_CTRL_SRC_TR_WIDTH)      // SRC_TR_WIDTH, sor transfer width, should set to HSIZE, here is 000, means 8bit
                      + (2 << DMA_CTRL_DINC)      // DINC, des addr increment, des is SPI, so should set to 1x, means no change
                      + (0 << DMA_CTRL_SINC)      // SINC, sor addr increment, src is sram, so should set to 00, means to increase 
                      + (1 << DMA_DEST_MSIZE)     // DEST_MSIZE, des burst length, set to 001 means 4 DST_TR_WIDTH per burst transcation
                      + (1 << DMA_SRC_MSIZE)     // SRC_MSIZE, sor burst length, set to 001 means 4 SOR_TR_WIDTH per burst transcation
                      + (1 << DMA_TTC_FC)     // TT_FC,transfer type and flow control,001 means memory to peripheral,dma is flow controller
                      + (0 << DMA_DMS)     // DMS, des master select, 0 means ahb master 0
                      + (0 << DMA_SMS)     // SMS, sor master select, 0 means ahb master 0
                      + (0 << DMA_LLP_DST_EN)     // LLP_DST_EN, des block chaining enable, set to 0 disable it
                      + (0 << DMA_LLP_SRC_EN) ;   // LLP_SOR_EN, sor block chaining enable, set to 0 disable it
  if (QSPI == QSPI0)
  {
    TxChannel->CFG_H = (REQ_QSPI0TX << DMA_CFG_SRC_PER) + (REQ_QSPI0TX << DMA_CFG_DEST_PER);
  }
  else if (QSPI == QSPI1)
  {
    TxChannel->CFG_H = (REQ_QSPI1TX << DMA_CFG_SRC_PER) + (REQ_QSPI1TX << DMA_CFG_DEST_PER);
  }
  else if (QSPI == QSPI2)
  {
    TxChannel->CFG_H = (REQ_QSPI2TX << DMA_CFG_SRC_PER) + (REQ_QSPI2TX << DMA_CFG_DEST_PER);
  }
  TxChannel->CFG_L = 0;
  TxChannel->CTL_L = temreg;
  TxChannel->DAR = (uint32_t)&QSPI->DATA;
  TxChannel->SAR = (uint32_t)buff;
  TxChannel->CTL_H = size;
  TxChannel->LLP = 0;

  QSPI->XFER = size;
  QSPI->CTRL1_SET = 1 << 13;
  QSPI->CTRL0_CLR = 0x04000000;
  QSPI->CTRL0_SET = 0x30000000;
  DMA->ChEnReg = 0x101 << channel;
  if (isEnIrq) return channel;
  DmaFreeChannel(channel);
  return 0;
}

int SpiTXFIFO(QSPI_TypeDef *QSPIptr, uint8_t *data, uint32_t num)
{
	//num<=16
	//FIFO is 4*32bit
	uint16_t i, j;
	volatile int waitnum = 0x100000;
	QSPI_DataInitTypeDef QSPI_DataInitStruct;

	for (i = 0; i < num / 4; i++)
	{
		QSPI_DataInitStruct.QSPI_DataLength = 4;
		QSPI_DataInitStruct.QSPI_DUPLEX = QSPI_HalfDuplex;
		QSPI_DataInitStruct.QSPI_TransferDir = QSPI_Transfer_Write;
		QSPI_DataConfig(QSPIptr, &QSPI_DataInitStruct);
		QSPIptr->DATA = *((uint32_t *)data + i);
	}

	num %= 4;
	if(num){
		uint8_t* pData = (uint8_t*)((uint32_t)QSPIptr+0x40);

		QSPI_DataInitStruct.QSPI_DataLength = num;
		QSPI_DataInitStruct.QSPI_DUPLEX = QSPI_HalfDuplex;
		QSPI_DataInitStruct.QSPI_TransferDir = QSPI_Transfer_Write;
		QSPI_DataConfig(QSPIptr, &QSPI_DataInitStruct);
		for(j=0;j<num;j++){
			*pData = data[i*4+j];
		}
	}
	return 0;
}

int SpiRXFIFO(QSPI_TypeDef* QSPIptr,uint8_t *data,uint32_t num)
{
	uint16_t i;
	uint32_t temp32;
	QSPI_DataInitTypeDef QSPI_DataInitStruct;

	for(i=0; i<num/4; i++) {
		QSPI_DataInitStruct.QSPI_DataLength = 4;
		QSPI_DataInitStruct.QSPI_DUPLEX = QSPI_HalfDuplex;
		QSPI_DataInitStruct.QSPI_TransferDir = QSPI_Transfer_Read;
		QSPI_DataConfig(QSPIptr, &QSPI_DataInitStruct);
    if (QSPI_GetFlagStatus(QSPIptr, QSPI_STATUS_RECV_NOT_EMPTY) == SET)
      *((uint32_t *)data + i) = QSPIptr->DATA;
  }

	num %= 4;
	if(num) {
		QSPI_DataInitStruct.QSPI_DataLength = num;
		QSPI_DataInitStruct.QSPI_DUPLEX = QSPI_HalfDuplex;
		QSPI_DataInitStruct.QSPI_TransferDir = QSPI_Transfer_Read;
		QSPI_DataConfig(QSPIptr, &QSPI_DataInitStruct);

		temp32 = QSPIptr->DATA;
		data[i*4] = temp32 & 0xff;
		if(num>1){
			data[i*4 + 1] = (temp32 >> 8) & 0xff;
		}
		if(num>2){
			data[i*4 + 2] = (temp32 >> 16) & 0xff;
		}
	}
    return 0;
}

#define BUFF_SIZE	      64
#define MASTER_INIT     1
#define SPI_DMA         1
#define SLAVER_WRITE    0
#define SLAVER_QSPI     QSPI2
#define SLAVER_QSPI_PIN QSPI2_GP5
#define MASTER_QSPI     QSPI2
#define MASTER_QSPI_PIN QSPI2_GP5
__align(4) static uint8_t SlaverBuffer[BUFF_SIZE] = {0};
__align(4) static uint8_t MasterBuffer[BUFF_SIZE] = {0};

int irqQspiChannel;
void qspiSlaverDma_IRQHandler(void)
{
  int i;
  // DMA->ClearTfr = 0x1;

  DmaChannelClearInterruptStatus(irqQspiChannel);
  for (i=0; i<BUFF_SIZE; i++)
  {
    // if(MasterBuffer[i] != SlaverBuffer[i])
    // {
    //   outl(0xdeaddead, SIM_FLAG);
    //   DmaFreeChannel(irqQspiChannel);
    //   while(1);
    // }
    printf("slaver=%d ",SlaverBuffer[i]);
    printf("master=%d ",MasterBuffer[i]);
  }
  DmaFreeChannel(irqQspiChannel);
	outl(0x5555aaaa, SIM_FLAG);
}

int spi_slaver_dma_test(void)
{
  int i;
  NVIC_InitTypeDef NVIC_InitStruct;
  NVIC_InitStruct.NVIC_IRQChannel = DMA_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
  NVIC_Init(&NVIC_InitStruct);

  if(MASTER_INIT == 1){
    qspi_flash_init(MASTER_QSPI, 4, QSPI_MASTER_MODE, 4, 4, MASTER_QSPI_PIN, 0);
#if SLAVER_WRITE
    GPIO_SetPinMux(GPIO1, GPIO_Pin_8, GPIO_FUNCTION_0); //GP5_0
    GPIO_SetPinDir(GPIO1, GPIO_Pin_8, GPIO_Mode_IN);
    GPIO_ConfigPull(GPIO1, GPIO_Pin_8, GPIO_PULL_DOWN);
    memset(MasterBuffer, 0, sizeof(MasterBuffer));

    while (GPIO_ReadPin(GPIO1, GPIO_Pin_8) == Bit_RESET)
      ;
    QSPI_CS_Low(MASTER_QSPI);
    irqQspiChannel = qspi_dma_read(MASTER_QSPI, MasterBuffer, BUFF_SIZE, ENABLE);
    QSPI_CS_High(MASTER_QSPI);
#else
    for (i = 0; i < BUFF_SIZE; i++)
      MasterBuffer[i] = i;
    QSPI_CS_Low(MASTER_QSPI);
    qspi_dma_write(MASTER_QSPI, MasterBuffer, BUFF_SIZE, DISABLE);
    QSPI_CS_High(MASTER_QSPI);

#endif
  }else{
    qspi_flash_init(SLAVER_QSPI, 4, QSPI_SLAVE_MODE, 4, 4, SLAVER_QSPI_PIN, 0);
#if SLAVER_WRITE
    GPIO_SetPinMux(GPIO1, GPIO_Pin_8, GPIO_FUNCTION_0); //GP5_0
    GPIO_SetPinDir(GPIO1, GPIO_Pin_8, GPIO_Mode_OUT);
    GPIO_ClearPin(GPIO1, GPIO_Pin_8);
    for (i = 0; i < BUFF_SIZE; i++)
      SlaverBuffer[i] = i + 1;
    qspi_dma_write(SLAVER_QSPI, SlaverBuffer, BUFF_SIZE, DISABLE);
    commonDelay(4000);
    GPIO_SetPin(GPIO1, GPIO_Pin_8);
    commonDelay(10);
    GPIO_ClearPin(GPIO1, GPIO_Pin_8);
#else

    memset(SlaverBuffer, 0, sizeof(SlaverBuffer));
    irqQspiChannel = qspi_dma_read(SLAVER_QSPI, SlaverBuffer, BUFF_SIZE, ENABLE);
    commonDelay(4000);

#endif
  }
}

void spi_slaver_fifo_test(void)
{
  int i;
  int size;
  int wait_time = 0x100000;
  if (MASTER_INIT == 1) {//master init
    qspi_flash_init(MASTER_QSPI, 4, QSPI_MASTER_MODE, 4, 16, MASTER_QSPI_PIN, 0); //QSPI0 = Master
#if SLAVER_WRITE
  GPIO_SetPinMux(GPIO1, GPIO_Pin_8, GPIO_FUNCTION_0);//GP5_0
  GPIO_SetPinDir(GPIO1, GPIO_Pin_8, GPIO_Mode_IN);
  GPIO_ConfigPull(GPIO1, GPIO_Pin_8, GPIO_PULL_DOWN);


  GPIO_SetPinMux(GPIO1, GPIO_Pin_9, GPIO_FUNCTION_0);//GP5_1
  GPIO_SetPinDir(GPIO1, GPIO_Pin_9, GPIO_Mode_OUT);
  GPIO_ClearPin(GPIO1, GPIO_Pin_9);
  MASTER_QSPI->CTRL1_SET = 0x00002000;  //DMA
  for (i = 0; i < BUFF_SIZE; i++)
    MasterBuffer[i] = 0;

  for (i = 0; i < BUFF_SIZE; i++)
    MasterBuffer[i] = 0;
  i = 0;
  QSPI_CS_Low(MASTER_QSPI);
  while(1){
    while ((GPIO_ReadPin(GPIO1, GPIO_Pin_8) == Bit_RESET) && wait_time--)
      ;
    if (wait_time < 0){
      printf("wait_time time out\r\n");
      break;
    }
    SpiRX(MASTER_QSPI, MasterBuffer + 16 * i, 16);
    i++;
    GPIO_SetPin(GPIO1, GPIO_Pin_9);
    commonDelay(10);
    GPIO_ClearPin(GPIO1, GPIO_Pin_9);
  }
  QSPI_CS_High(MASTER_QSPI);
  for ( i = 0; i <BUFF_SIZE; i++)
  {
    printf("%d ",MasterBuffer[i]);
  }

#else

  GPIO_SetPinMux(GPIO1, GPIO_Pin_8, GPIO_FUNCTION_0);//GP5_0
  GPIO_SetPinDir(GPIO1, GPIO_Pin_8, GPIO_Mode_OUT);
  GPIO_ClearPin(GPIO1, GPIO_Pin_8);
  MASTER_QSPI->CTRL1_SET = 0x00002000;  //DMA
  size = BUFF_SIZE / 16;
  for(i=0;i<BUFF_SIZE;i++)
    MasterBuffer[i] = i + 2;

  QSPI_CS_Low(MASTER_QSPI);
  
  for ( i = 0; i < size; i++)
  {
    SpiTX(MASTER_QSPI, MasterBuffer + 16*i, 16);
    GPIO_SetPin(GPIO1, GPIO_Pin_8);
    commonDelay(10);
    GPIO_ClearPin(GPIO1, GPIO_Pin_8);
  }
  if(BUFF_SIZE % 16) {
    SpiTX(MASTER_QSPI, MasterBuffer + 16 * size, BUFF_SIZE % 16);
    GPIO_SetPin(GPIO1, GPIO_Pin_8);
    commonDelay(10);
    GPIO_ClearPin(GPIO1, GPIO_Pin_8);
  }
  QSPI_CS_High(MASTER_QSPI);
#endif
  } else {//slaver init
    qspi_flash_init(SLAVER_QSPI, 4, QSPI_SLAVE_MODE, 4, 1, SLAVER_QSPI_PIN, 0); //QSPI1 = Slaver
#if SLAVER_WRITE
  GPIO_SetPinMux(GPIO1, GPIO_Pin_8, GPIO_FUNCTION_0);//GP5_0
  GPIO_SetPinDir(GPIO1, GPIO_Pin_8, GPIO_Mode_OUT);
  GPIO_ClearPin(GPIO1, GPIO_Pin_8);
  
  
  GPIO_SetPinMux(GPIO1, GPIO_Pin_9, GPIO_FUNCTION_0);//GP5_1
  GPIO_SetPinDir(GPIO1, GPIO_Pin_9, GPIO_Mode_IN);
  GPIO_ConfigPull(GPIO1, GPIO_Pin_9, GPIO_PULL_DOWN);

  SLAVER_QSPI->CTRL1_SET = 0x2000;
  for(i=0;i<BUFF_SIZE;i++)
    SlaverBuffer[i] = i;
  size = BUFF_SIZE / 16;
  for (i = 0; i < size; i++)
  {
    SpiTXFIFO(SLAVER_QSPI, SlaverBuffer + 16 * i, 16);
    GPIO_SetPin(GPIO1, GPIO_Pin_8);
    commonDelay(10);
    GPIO_ClearPin(GPIO1, GPIO_Pin_8);
    while (GPIO_ReadPin(GPIO1, GPIO_Pin_9) == Bit_RESET)
      ;
  }
  if (BUFF_SIZE % 16) {
    SpiTXFIFO(SLAVER_QSPI, SlaverBuffer + 16 * size,BUFF_SIZE % 16);
    GPIO_SetPin(GPIO1, GPIO_Pin_8);
    commonDelay(10);
    GPIO_ClearPin(GPIO1, GPIO_Pin_8);
    while (GPIO_ReadPin(GPIO1, GPIO_Pin_9) == Bit_RESET)
      ;
  }
#else
  GPIO_SetPinMux(GPIO1, GPIO_Pin_8, GPIO_FUNCTION_0);//GP5_0
  GPIO_SetPinDir(GPIO1, GPIO_Pin_8, GPIO_Mode_IN);
  GPIO_ConfigPull(GPIO1, GPIO_Pin_8, GPIO_PULL_DOWN);
  SLAVER_QSPI->CTRL0 = 0x34000000;  //bit26 & bit29 Read & Run


  for (i=0;i<BUFF_SIZE;i++)
    SlaverBuffer[i] = 0;
  i = 0;
  while(1){
    while ((GPIO_ReadPin(GPIO1, GPIO_Pin_8) == Bit_RESET) && wait_time--)
      ;
    if (wait_time < 0) break;
    SpiRXFIFO(SLAVER_QSPI, SlaverBuffer + 16*i, 16);
    i++;
  }
  for ( i = 0; i <BUFF_SIZE; i++)
  {
    printf("%d ",SlaverBuffer[i]);
  }
  
#endif
  }

	outl(0x5555aaaa, SIM_FLAG);
  while(1);
}

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main()
{   
  UART_Configuration(UART1, 115200, UART1_GP2);
	printf("\r\r\n-----------------ASM1130 Standard Peripheral Library Driver-----------------\r\r\n");
#if SPI_DMA 
  spi_slaver_dma_test();
#else
  spi_slaver_fifo_test();
#endif
  while(1);
}


